package com.tsyz.netty.client;

import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;

import java.util.concurrent.TimeUnit;

public class ClientHandler extends ChannelInboundHandlerAdapter {
    /**
     * 存储与当前处理器关联的NettyClient实例，用于处理客户端连接状态变化时的回调操作。
     */
    private final NettyClient client;

    /**
     * 构造一个新的ClientHandler对象，用于处理与指定NettyClient的交互。
     *
     * @param client 要与之交互的NettyClient实例。
     */
    public ClientHandler(NettyClient client) {
        this.client = client;
    }

    /**
     * 处理从客户端接收到的消息。
     *
     * @param ctx ChannelHandlerContext 上下文对象。
     * @param msg Object 接收到的消息对象。
     */
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) {
        System.out.println("客户端--接受--： " + msg);
    }

    /**
     * 处理 ChannelHandler 中的异常情况。
     *
     * @param ctx   ChannelHandlerContext 上下文对象，用于关闭连接。
     * @param cause Throwable 异常对象，用于打印错误信息。
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        System.err.println("异常: " + cause.getMessage());
        ctx.close();
    }

    /**
     * 处理 Channel 不活跃事件，打印连接关闭信息并调用客户端的断开连接处理方法。
     *
     * @param ctx ChannelHandlerContext 上下文对象，用于获取当前 Channel 的状态信息。
     */
    @Override
    public void channelInactive(ChannelHandlerContext ctx) {
        System.out.println("连接关闭");
        client.handleDisconnect();
    }

    /**
     * 在通道活跃时开启心跳检测任务。
     *
     * @param ctx ChannelHandlerContext 上下文对象，用于获取通道信息和调度任务。
     */
    @Override
    public void channelActive(ChannelHandlerContext ctx) {
        // 当通道活跃时，开启心跳检测任务
        scheduleHeartbeat(ctx);
    }

    /**
     * 定期发送心跳消息来检测连接是否活着。
     *
     * @param ctx ChannelHandlerContext 上下文对象，用于写入和调度心跳消息。
     */
    private void scheduleHeartbeat(ChannelHandlerContext ctx) {
        // 定期发送心跳消息来检测连接是否活着
        ctx.executor().schedule(() -> {
            if (ctx.channel().isActive()) {
                ctx.writeAndFlush("心跳").addListener(ChannelFutureListener.CLOSE_ON_FAILURE);
                scheduleHeartbeat(ctx); // 继续调度下一个心跳
            }
        }, 5, TimeUnit.SECONDS); // 每5秒发送一次心跳
    }
}
